package com.xiguanlezz.cn.client.naming;

import com.xiguanlezz.cn.api.common.Constants;
import com.xiguanlezz.cn.api.naming.NamingService;
import com.xiguanlezz.cn.api.naming.listener.EventListener;
import com.xiguanlezz.cn.api.naming.pojo.Instance;
import com.xiguanlezz.cn.client.env.NacosClientProperties;
import com.xiguanlezz.cn.client.naming.cache.ServiceInfoHolder;
import com.xiguanlezz.cn.client.naming.event.InstancesChangeEvent;
import com.xiguanlezz.cn.client.naming.event.InstancesChangeNotifier;
import com.xiguanlezz.cn.client.naming.remote.NamingClientProxy;
import com.xiguanlezz.cn.client.naming.remote.NamingClientProxyDelegate;
import com.xiguanlezz.cn.client.naming.utils.InitUtils;
import com.xiguanlezz.cn.common.notify.NotifyCenter;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/11/16 17:03
 * @Description：服务注册/发现实现类
 */
public class NacosNamingService implements NamingService {
    // 真正执行注册的对象
    private NamingClientProxy clientProxy;

    // 每个NacosNamingService有自己的namespace
    private String namespace;
    // 客户端关于服务实例缓存的实体类
    private ServiceInfoHolder serviceInfoHolder;
    // 每个NamingService都有单独的notifierEventScope
    private String notifierEventScope;
    // 服务实例更新事件订阅器
    private InstancesChangeNotifier changeNotifier;


    public NacosNamingService(Properties properties) {
        init(properties);
    }

    private void init(Properties properties) {
        NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
        this.namespace = InitUtils.initNamespaceForNaming(nacosClientProperties);
        this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, nacosClientProperties);
        this.clientProxy = new NamingClientProxyDelegate(this.namespace, this.serviceInfoHolder, nacosClientProperties);
        notifierEventScope = UUID.randomUUID().toString();
        InstancesChangeNotifier instancesChangeNotifier = new InstancesChangeNotifier(notifierEventScope);
        // 往通知中心注册服务实例事件生产器
        NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
        // 往通知中心注册服务实例更新事件订阅器
        NotifyCenter.registerSubscriber(instancesChangeNotifier);
    }

    @Override
    public void registerInstance(String serviceName, String ip, int port) throws Exception {
        this.registerInstance(serviceName, Constants.DEFAULT_GROUP, ip, port);
    }

    @Override
    public void registerInstance(String serviceName, String groupName, String ip, int port) throws Exception {
        Instance instance = new Instance();
        instance.setServiceName(serviceName);
        instance.setIp(ip);
        instance.setPort(port);
        registerInstance(serviceName, groupName, instance);
    }


    @Override
    public void registerInstance(String serviceName, Instance instance) throws Exception {
        registerInstance(serviceName, Constants.DEFAULT_GROUP, instance);
    }

    @Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws Exception {
        clientProxy.registerService(serviceName, groupName, instance);
    }

    @Override
    public void deregisterInstance(String serviceName, String ip, int port) throws Exception {
        deregisterInstance(serviceName, Constants.DEFAULT_GROUP, ip, port);
    }

    @Override
    public void deregisterInstance(String serviceName, String groupName, String ip, int port) throws Exception {
        Instance instance = new Instance();
        instance.setServiceName(serviceName);
        instance.setIp(ip);
        instance.setPort(port);
        deregisterInstance(serviceName, groupName, instance);
    }

    @Override
    public void deregisterInstance(String serviceName, Instance instance) throws Exception {
        clientProxy.deregisterService(serviceName, Constants.DEFAULT_GROUP, instance);
    }

    @Override
    public void deregisterInstance(String serviceName, String groupName, Instance instance) throws Exception {
        clientProxy.deregisterService(serviceName, groupName, instance);
    }

    @Override
    public void subscribe(String serviceName, EventListener listener) throws Exception {
        subscribe(serviceName, Constants.DEFAULT_GROUP, new ArrayList<>(), listener);
    }

    @Override
    public void subscribe(String serviceName, String groupName, EventListener listener) throws Exception {
        subscribe(serviceName, groupName, new ArrayList<>(), listener);
    }

    @Override
    public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws Exception {
        subscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
    }

    @Override
    public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws Exception {
        if (Objects.isNull(listener)) {
            return;
        }
        String clusterString = StringUtils.join(clusters, ",");
        // 注册服务实例更新事件的监听器
        changeNotifier.registerListener(serviceName, groupName, clusterString, listener);
        clientProxy.subscribe(serviceName, groupName, clusterString);
    }

    @Override
    public void unsubscribe(String serviceName, EventListener listener) throws Exception {
        unsubscribe(serviceName, Constants.DEFAULT_GROUP, new ArrayList<>(), listener);
    }

    @Override
    public void unsubscribe(String serviceName, String groupName, EventListener listener) throws Exception {
        unsubscribe(serviceName, groupName, new ArrayList<>(), listener);
    }

    @Override
    public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws Exception {
        unsubscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
    }

    @Override
    public void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws Exception {
        if (Objects.isNull(listener)) {
            return;
        }
        String clusterString = StringUtils.join(clusters, ",");
        // 移除服务实例更新事件的监听器
        changeNotifier.deregisterListener(serviceName, groupName, clusterString, listener);
        if (!changeNotifier.isSubscribed(serviceName, groupName, clusterString)) {
            // 如果此时没有服务实例更新事件的监听器了，那就执行不带监听器的取消订阅方法
            clientProxy.unsubscribe(serviceName, groupName, clusterString);
        }
    }

}
